package cn.tedu.store.search.webapi.service.impl;

import cn.tedu.store.commons.pojo.search.entity.EsProduct;
import cn.tedu.store.commons.web.JsonPage;
import cn.tedu.store.search.service.IEsProductService;
import cn.tedu.store.search.webapi.mapper.EsProductMapper;
import cn.tedu.store.search.webapi.repository.SpuRepository;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.common.lucene.search.function.FunctionScoreQuery;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;


import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
public class EsProductServiceImpl implements IEsProductService {

    @Autowired
    private EsProductMapper esProductMapper;

    @Autowired
    private SpuRepository spuRepository;

    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;


    @Override
    public int importAll() {
        List<EsProduct> list = esProductMapper.getAllEsProductList(null);
        Iterable<EsProduct> products = spuRepository.saveAll(list);
        Iterator<EsProduct> iterator = products.iterator();
        int count = 0;
        while(iterator.hasNext()){
            ++count;
            iterator.next();
        }
        return count;//成功导入的商品数量
    }

    @Override
    public void delete(Long id) {
        spuRepository.deleteById(id);
    }

    @Override
    public EsProduct create(Long id) {
        EsProduct result = null;
        List<EsProduct> esProductList = esProductMapper.getAllEsProductList(id);
        if (esProductList.size() > 0) {
            EsProduct esProduct = esProductList.get(0);
            result = spuRepository.save(esProduct);
        }
        return result;//成功导入的商品信息
    }

    @Override
    public void delete(List<Long> ids) {
        if (!CollectionUtils.isEmpty(ids)) {
            List<EsProduct> esProductList = new ArrayList<>();
            for (Long id : ids) {
                EsProduct esProduct = new EsProduct();
                esProduct.setId(id);
                esProductList.add(esProduct);
            }
            spuRepository.deleteAll(esProductList);
        }
    }

    @Override
    public JsonPage<EsProduct> searchSimple(String keyword, Integer pageNum, Integer pageSize) {
        log.info("参数:{},{},{}",keyword,pageNum,pageSize);
        Pageable pageable = PageRequest.of(pageNum, pageSize);
        return JsonPage.restPage(spuRepository.queryEsProductsByNameMatchesOrTypeNumberMatchesOrTitleMatchesOrDescriptionOrKeywordsMatches(
                keyword, keyword, keyword, keyword, keyword ,pageable));
    }

    @Override
    public JsonPage<EsProduct> search(String keyword, Long brandId, Long categoryId, Integer pageNum, Integer pageSize, Integer sort) {
        log.info("参数:{},{},{},{},{},{}",keyword,brandId,categoryId,pageNum,pageSize,sort);
        Pageable pageable = PageRequest.of(pageNum, pageSize);
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        //分页
        nativeSearchQueryBuilder.withPageable(pageable);
        //过滤
        if (brandId != null || categoryId != null) {
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            if (brandId != null) {
                boolQueryBuilder.must(QueryBuilders.termQuery("brandId", brandId));
            }
            if (categoryId != null) {
                boolQueryBuilder.must(QueryBuilders.termQuery("categoryId", categoryId));
            }
            nativeSearchQueryBuilder.withFilter(boolQueryBuilder);
        }
        //搜索
        if (keyword.length() == 0) {
            log.info("keyword为空");
            nativeSearchQueryBuilder.withQuery(QueryBuilders.matchAllQuery());
        } else {
            log.info("keyword不为空");
            List<FunctionScoreQueryBuilder.FilterFunctionBuilder> filterFunctionBuilders = new ArrayList<>();
            filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("name", keyword),
                    ScoreFunctionBuilders.weightFactorFunction(10)));
            filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("title", keyword),
                    ScoreFunctionBuilders.weightFactorFunction(5)));
            filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("keywords", keyword),
                    ScoreFunctionBuilders.weightFactorFunction(2)));
            FunctionScoreQueryBuilder.FilterFunctionBuilder[] builders = new FunctionScoreQueryBuilder.FilterFunctionBuilder[filterFunctionBuilders.size()];
            filterFunctionBuilders.toArray(builders);
            FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(builders)
                    .scoreMode(FunctionScoreQuery.ScoreMode.SUM)
                    .setMinScore(2);
            nativeSearchQueryBuilder.withQuery(functionScoreQueryBuilder);
        }
        //排序
        if(sort==1){
            //按新品从新到旧
            nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("id").order(SortOrder.DESC));
        }else if(sort==2){
            //按销量从高到低
            nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("sales").order(SortOrder.DESC));
        }else if(sort==3){
            //按价格从低到高
            nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("listPrice").order(SortOrder.ASC));
        }else if(sort==4){
            //按价格从高到低
            nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("listPrice").order(SortOrder.DESC));
        }else{
            //按相关度
            nativeSearchQueryBuilder.withSort(SortBuilders.scoreSort().order(SortOrder.DESC));
        }
        nativeSearchQueryBuilder.withSort(SortBuilders.scoreSort().order(SortOrder.DESC));
        NativeSearchQuery searchQuery = nativeSearchQueryBuilder.build();
        log.info("DSL:{}", searchQuery.getQuery().toString());
        SearchHits<EsProduct> searchHits = elasticsearchRestTemplate.search(searchQuery, EsProduct.class);
        if(searchHits.getTotalHits()<=0){
            log.info("searchHits.getTotalHits()<=0");
            return JsonPage.restPage(new PageImpl<>(new ArrayList<>(),pageable,0));
        }
        log.info("searchHits.getTotalHits()>0");
        List<EsProduct> searchProductList = searchHits.stream().map(SearchHit::getContent).collect(Collectors.toList());
        return JsonPage.restPage(new PageImpl<>(searchProductList,pageable,searchHits.getTotalHits()));
    }

}
